#ifndef unigame_DoubleLink_h
#define unigame_DoubleLink_h

#include "config/Def.h"

namespace unigame
{
	template <class T>
	struct LinkListItem
	{
		LinkListItem<T>* m_next;
		LinkListItem<T>* m_last;
		T m_value;

		LinkListItem(T value):m_value(value), m_next(0), m_last(0){}
		LinkListItem():m_next(0), m_last(0){}
	};

	template <class T>
	class LinkList
	{
	public:
		LinkList(bool isReleaseMemory):m_length(0), m_head(0), m_end(0), m_isReleaseMemory(isReleaseMemory){}
		
		~LinkList()
		{
			clear(true);
		}

		void clear(bool isRelease = true)
		{
			if(isRelease && m_isReleaseMemory)
			{
				LinkListItem<T>* temp;
				while(m_head)
				{
					temp = m_head;
					m_head = m_head->m_next;
					delete temp;
				}
			}
			m_head = 0;
			m_end = 0;
		}

		LinkListItem<T>* first()
		{
			return m_head;
		}

		LinkListItem<T>* end()
		{
			return m_end;
		}

		LinkListItem<T>* addFirst(T value)
		{
			assert(m_isReleaseMemory && "must release memory");
			return selfAddFirst(uni_new LinkListItem<T>(value));
		}

		LinkListItem<T>* addFirst(LinkListItem<T>* item)
		{
			assert(!m_isReleaseMemory && "must not release memory");
			return selfAddFirst(item);
		}

		LinkListItem<T>* addLast(T value)
		{
			assert(m_isReleaseMemory && "must release memory");
			return selfAddLast(uni_new LinkListItem<T>(value));
		}

		LinkListItem<T>* addLast(LinkListItem<T>* item)
		{
			assert(!m_isReleaseMemory && "must not release memory");
			return selfAddLast(item);
		}

		LinkListItem<T>* addBefore(T value, LinkListItem<T>* target)
		{
			assert(m_isReleaseMemory && "must release memory");
			assert(target && "target must not null");
			return selfAddBefore(uni_new LinkListItem<T>(value), target);
		}

		LinkListItem<T>* addBefore(LinkListItem<T>* item, LinkListItem<T>* target)
		{
			assert(!m_isReleaseMemory && "must not release memory");
			assert(target && "target must not null");
			return selfAddBefore(item, target);
		}

		LinkListItem<T>* addAfter(T value, LinkListItem<T>* target)
		{
			assert(m_isReleaseMemory && "must release memory");
			assert(target && "target must not null");
			return selfAddAfter(uni_new LinkListItem<T>(value), target);
		}

		LinkListItem<T>* addAfter(LinkListItem<T>* item, LinkListItem<T>* target)
		{
			assert(!m_isReleaseMemory && "must not release memory");
			assert(target && "target must not null");
			return selfAddAfter(item, target);
		}

		LinkListItem<T>* removeFirst()
		{
			assert(!m_isReleaseMemory && "must not release memory");
			return selfRemoveFirst();
		}

		T* removeFirstAndRelease()
		{
			assert(m_isReleaseMemory && "must release memory");
			LinkListItem<T>* temp = selfRemoveFirst();
			if(temp)
			{
				T* res = &(temp->m_value);
				delete temp;
				return res;
			}
			return 0;
		}

		LinkListItem<T>* removeLast()
		{
			assert(!m_isReleaseMemory && "must not release memory");
			return selfRemoveLast();
		}

		T* removeLastAndRelease()
		{
			assert(m_isReleaseMemory && "must release memory");
			LinkListItem<T>* temp = selfRemoveLast();
			if(temp)
			{
				T* res = &(temp->m_value);
				delete temp;
				return res;
			}
			return 0;
		}

		T* removeAndRelease(LinkListItem<T>* item)
		{
			assert(m_isReleaseMemory && "must release memory");
			assert(item && "remove item must not null");
			LinkListItem<T>* temp = selfRemove(item);
			if(temp)
			{
				T* res = &(temp->m_value);
				delete temp;
				return res;
			}
			return 0;
		}

		LinkListItem<T>* remove(LinkListItem<T>* item)
		{
			assert(!m_isReleaseMemory && "must not release memory");
			assert(item && "remove item must not null");
			return selfRemove(item);
		}

		T* removeBeforeAndRelease(LinkListItem<T>* target)
		{
			assert(m_isReleaseMemory && "must release memory");
			assert(target && "target item must not null");
			LinkListItem<T>* temp = selfRemoveBefore(target);
			if(temp)
			{
				T* res = &(temp->m_value);
				delete temp;
				return res;
			}
			return 0;
		}

		LinkListItem<T>* removeBefore(LinkListItem<T>* target)
		{
			assert(!m_isReleaseMemory && "must not release memory");
			assert(target && "target item must not null");
			return selfRemoveBefore(target);
		}

		T* removeAfterAndRelease(LinkListItem<T>* target)
		{
			assert(m_isReleaseMemory && "must release memory");
			assert(target && "target item must not null");
			LinkListItem<T>* temp = selfRemoveAfter(target);
			if(temp)
			{
				T* res = &(temp->m_value);
				delete temp;
				return res;
			}
			return 0;
		}

		LinkListItem<T>* removeAfter(LinkListItem<T>* target)
		{
			assert(!m_isReleaseMemory && "must not release memory");
			assert(target && "target item must not null");
			return selfRemoveAfter(target);
		}

		void append(LinkList<T>& list)
		{
			assert(m_isReleaseMemory == list.m_isReleaseMemory && "list release not match");
			if(!m_head)
			{
				m_head = list.first();
				m_end = list.end();
			}
			else if(list.first())
			{
				m_end->m_next = list.first();
				list.first()->m_last = m_end;
				m_end = list.end();
			}
			list.clear(false);
		}

	private:
		LinkListItem<T>* selfAddFirst(LinkListItem<T>* item)
		{
			++m_length;
			if(!m_head)
			{
				m_head = item;
				m_end = item;
				item->m_last = 0;
				item->m_next = 0;
			}
			else
			{
				item->m_next = m_head;
				item->m_last = 0;
				m_head->m_last = item;
				m_head = item;
			}
			return item;
		}

		LinkListItem<T>* selfAddLast(LinkListItem<T>* item)
		{
			++m_length;
			if(!m_head)
			{
				m_head = item;
				m_end = item;
				item->m_last = 0;
				item->m_next = 0;
			}
			else
			{
				item->m_last = m_end;
				item->m_next = 0;
				m_end->m_next = item;
				m_end = item;
			}
			return item;
		}

		LinkListItem<T>* selfAddBefore(LinkListItem<T>* item, LinkListItem<T>* target)
		{
			if(target == m_head)
			{
				return selfAddFirst(item);
			}
			++m_length;
			item->m_next = target;
			item->m_last = target->m_last;
			item->m_last->m_next = item;
			target->m_last = item;
			return item;
		}

		LinkListItem<T>* selfAddAfter(LinkListItem<T>* item, LinkListItem<T>* target)
		{
			if(target == m_end)
			{
				return selfAddLast(item);
			}
			return selfAddBefore(item, target->m_next);
		}

		LinkListItem<T>* selfRemoveFirst()
		{
			if(m_length <= 0)
			{
				return 0;
			}
			--m_length;
			LinkListItem<T>* temp = m_head;
			if(m_length == 0)
			{
				m_head = 0;
				m_end = 0;
			}
			else
			{
				m_head = m_head->m_next;
				m_head->m_last = 0;
			}
			return temp;
		}

		LinkListItem<T>* selfRemoveLast()
		{
			if(m_length <= 0)
			{
				return 0;
			}
			--m_length;
			LinkListItem<T>* temp = m_end;
			if(m_length == 0)
			{
				m_head = 0;
				m_end = 0;
			}
			else
			{
				m_end = m_end->m_last;
				m_end->m_next = 0;
			}
			return temp;
		}

		LinkListItem<T>* selfRemoveBefore(LinkListItem<T>* target)
		{
			if(target == m_head)
			{
				return 0;
			}
			if(target == m_head->m_next)
			{
				return selfRemoveFirst();
			}
			--m_length;
			LinkListItem<T>* temp = target->m_last;
			target->m_last = temp->m_last;
			temp->m_last->m_next = target;
			return temp;
		}

		LinkListItem<T>* selfRemoveAfter(LinkListItem<T>* target)
		{
			if(target == m_end)
			{
				return 0;
			}
			if(target == m_end->m_last)
			{
				return selfRemoveLast();
			}
			return selfRemoveBefore(target->m_next->m_next);
		}

		LinkListItem<T>* selfRemove(LinkListItem<T>* item)
		{
			if(item == m_head)
			{
				return selfRemoveFirst();
			}
			if(item == m_end)
			{
				return selfRemoveLast();
			}
			--m_length;
			item->m_last->m_next = item->m_next;
			item->m_next->m_last = item->m_last;
			return item;
		}

	private:
		LinkListItem<T>* m_head;
		LinkListItem<T>* m_end;
		int32u m_length;
		bool m_isReleaseMemory;
	};
}

#endif